home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.04 Apr 95 / Performance / Fractal 1 / FractalEngine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-13  |  10.8 KB  |  454 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:            FractalEngine.c
  3.     
  4.     Used to build:    “Fractal 1”
  5.     
  6.     Written by:        Jim Cathey            July 1985
  7.                     Eric Traut            November 1994
  8.  
  9.     Description:
  10.         The following code implements a “Fractal Contour” generating
  11.         program. See comments in the file “FractalMain.c” for more
  12.         information.
  13.         
  14.         The code in this file implements the fractal-generating
  15.         and plotting portion of the program.
  16. */
  17.  
  18.  
  19. #include <Quickdraw.h>
  20. #include <ToolUtils.h>
  21.  
  22. #include <stdlib.h>
  23.  
  24. #include "Fractal.h"
  25.  
  26. /* Functions defined within this file */
  27. double RandomDouble(void);
  28. void CalcXs(short len, short incr, short sk);
  29. void CalcYs(short len, short incr, short sk);
  30. void CalcDiagonals(short len, short incr, short sk);
  31. short GetZValue(short x, short y);
  32. void SetZValue(short d, short x, short y);
  33. void SeaLevel(short *newx, short *newy, short *newz);
  34. short ScaleValue(short base, short numer, short denom);
  35. void DoPlot(short xindex, short yindex);
  36. void PlotTo(short x, short y, short z);
  37. void Rotate(short *x, short *y);
  38. void TiltDown(short *x, short *z);
  39. void DrawLine(short x, short y);
  40. void Cordic(short *x, short *y, short scale, short count);
  41. void ScaledMoveTo(short x, short y);
  42. void ScaledLineTo(short x, short y);
  43.  
  44. /* Global variables */
  45. short             gMaxX, gMaxY;
  46. Boolean         gAtLineStart;            /* True at the first of the line. */
  47. Boolean         gOnLand;                /* True when plotting land, else false. */
  48.  
  49.  
  50. /*
  51.     RandomDouble
  52.     
  53.     This function returns a random number between -1 and 1.
  54. */
  55. double RandomDouble(void)
  56. {
  57.     return (double)rand() / RAND_MAX;
  58. }
  59.  
  60.  
  61. /*
  62.     CalcSurface
  63.     
  64.     This is the main surface-generating routine. It generates a random
  65.     fractal surface by filling in the gPointArray array.
  66. */
  67. void CalcSurface(short level)
  68. {
  69.     short             i, j, length, incrby, sk;
  70.     float             power;
  71.     CursHandle         waitCursor;
  72.     long            startTicks;
  73.  
  74.     waitCursor = GetCursor(watchCursor);
  75.     if (waitCursor)
  76.         SetCursor(*waitCursor);              /* Show busy cursor */
  77.  
  78.     gTotalFractals++;
  79.     gTimeUpdate = true;
  80.     startTicks = TickCount();
  81.     
  82.     gMaxX = 1 << level;
  83.     gMaxY = gMaxX / 2;
  84.     for (i = 0; i <= gMaxX; i++)               /* Clear the Array.  Use i & incrby as temps */
  85.     for (incrby = 0; incrby <= gMaxY; incrby++)
  86.         (*gPointArray)[i][incrby] = 0;
  87.  
  88.     for (i = 1; i <= level; i++) {
  89.         for (power = 1.0, j = 0; j < i; j++)
  90.             power *= 1.8;
  91.         length = 10000 / power;                /* = 10000 / (1.8^i) */
  92.         incrby = gMaxX / (1 << i);             /* # of line segments in a side of the triangle */
  93.         sk = incrby * 2;
  94.         CalcXs(length, incrby, sk);
  95.         CalcYs(length, incrby, sk);
  96.         CalcDiagonals(length, incrby, sk);
  97.     }
  98.     
  99.     gTotalTickCount += TickCount() - startTicks;
  100.     InitCursor();                            /* Put back the arrow */
  101. }
  102.  
  103.  
  104. /*
  105.     CalcXs
  106.     
  107.     This function calculates the fractal values in the X direction.
  108.     It is called for each level and subdivides the existing edges
  109.     of the fractal to get the next level.
  110. */
  111. void CalcXs(short len, short incr, short sk)
  112. {
  113.     short             y, x;
  114.     short             d1, d2;
  115.  
  116.     for (y=0; y < gMaxX; y += sk) {
  117.         for (x = incr+y; x <= gMaxX; x += sk) {
  118.             d1 = GetZValue(x-incr, y);
  119.             d2 = GetZValue(x+incr, y);
  120.             SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  121.         }
  122.     }
  123. }
  124.  
  125.  
  126. /*
  127.     CalcYs
  128.  
  129.     This function calculates the fractal values in the Y direction.
  130.     It is called for each level and subdivides the existing edges
  131.     of the fractal to get the next level.
  132. */
  133. void CalcYs(short len, short incr, short sk)
  134. {
  135.     short y, x;
  136.     short d1, d2;
  137.  
  138.     for (x = gMaxX; x >= 1; x -= sk)
  139.         for (y = incr; y <= x; y += sk) {
  140.             d1 = GetZValue(x, y + incr);
  141.             d2 = GetZValue(x, y - incr);
  142.             SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  143.         }
  144. }
  145.  
  146.  
  147. /*
  148.     CalcDiagonals
  149.  
  150.     This function calculates the fractal values in the diagonal direction.
  151.     It is called for each level and subdivides the existing edges
  152.     of the fractal to get the next level.
  153. */
  154. void CalcDiagonals(short len, short incr, short sk)
  155. {
  156.     short             y, x;
  157.     short             d1, d2;
  158.         
  159.     for (x = 0; x < gMaxX; x += sk)
  160.     for (y = incr; y <= gMaxX - x; y += sk) {
  161.         d1 = GetZValue(x + y - incr, y - incr);
  162.         d2 = GetZValue(x + y + incr, y + incr);
  163.         SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x + y, y);
  164.     }
  165. }
  166.  
  167.  
  168. /*
  169.     GetZValue
  170.  
  171.     This function returns the Z value (i.e. the value stored in the
  172.     two-dimensional gPlotArray array. Because the fractal is triangular
  173.     and the array is square, we will store half the triange in the lower
  174.     part of the array the the other half in the upper part of the
  175.     array.
  176. */
  177. short GetZValue(short x, short y)
  178. {
  179.     if (y <= gMaxY)
  180.         return (*gPointArray)[x][y];
  181.     else
  182.         return (*gPointArray)[gMaxX - x][gMaxX + 1 - y];
  183. }
  184.  
  185.  
  186. /*
  187.     SetZValue
  188.  
  189.     This function saves the Z value (i.e. the value in the
  190.     two-dimensional gPlotArray array. Because the fractal is triangular
  191.     and the array is square, we will store half the triange in the lower
  192.     part of the array the the other half in the upper part of the
  193.     array.
  194. */
  195. void SetZValue(short d, short x, short y)
  196. {
  197.     if (y <= gMaxY)
  198.         (*gPointArray)[x][y] = d;
  199.     else
  200.         (*gPointArray)[gMaxX - x][gMaxX + 1 - y] = d;
  201. }
  202.  
  203.  
  204. /*
  205.     PlotData
  206.     
  207.     Our window is already open at this point, and it is cleared.
  208.     All we have to do now is fill it. This function draws the 
  209.     2D projection of the triangular database on the screen.
  210. */
  211. void PlotData(void)
  212. {
  213.     short             xindex, yindex;
  214.  
  215.     gOnLand = true;                                        /* On land to start */
  216.  
  217.     for (xindex = 0; xindex <= gMaxX; xindex++) {        /* Plot along X axis */
  218.         gAtLineStart = true;
  219.         for (yindex = 0; yindex <= xindex; yindex++)
  220.             DoPlot(xindex, yindex);
  221.     }
  222.     
  223.     for (yindex = 0; yindex <= gMaxX; yindex++) {        /* Plot along Y axis */
  224.         gAtLineStart = true;
  225.         for (xindex = yindex; xindex <= gMaxX; xindex++)
  226.             DoPlot(xindex, yindex);
  227.     }
  228.     
  229.     for (xindex = 0; xindex <= gMaxX; xindex++) {        /* Plot along the diagonal */
  230.         gAtLineStart = true;
  231.         for (yindex = 0; yindex <= gMaxX - xindex; yindex++)
  232.             DoPlot(xindex + yindex, yindex);
  233.     }
  234. }
  235.  
  236.  
  237. /*
  238.     DoPlot
  239.     
  240.     This function plots a single line or point from the current X and
  241.     Y value to the new X and Y value specified.
  242. */
  243. void DoPlot(short xindex, short yindex)
  244. {
  245.     short        xcoord, ycoord, zcoord;
  246.  
  247.     zcoord = GetZValue(xindex, yindex);
  248.     ycoord = ScaleValue(yindex, 10000, gMaxX);
  249.     xcoord = ScaleValue(xindex, 10000, gMaxX) - ycoord/2;
  250.     if (gContourType == kStyleWater)
  251.         SeaLevel(&xcoord, &ycoord, &zcoord);
  252.     PlotTo(xcoord, ycoord, zcoord);
  253. }
  254.  
  255.  
  256. /*
  257.     SeaLevel
  258.     
  259.     This function is used to plot lines when using the “foothills
  260.     with water” mode. It determines whether a line goes under
  261.     water at any point. If it does, it simply draws a point
  262.     to represent the water.
  263. */
  264. void SeaLevel(short *newX, short *newY, short *newZ)
  265. {
  266.     static short     oldX, oldY, oldZ;            /* The starting point for the next call */
  267.     short             waterX, waterY, waterZ;     /* Where the vector hits the waterline. */
  268.     float             scratch;
  269.  
  270.     if (gAtLineStart) {                        /* If at the beginning of the line */
  271.         if ((oldZ = *newZ) < 0) {            /*  and if we’re underwater */
  272.             ForeColor(blueColor);
  273.             gOnLand = false;
  274.             *newZ = 0;                        /* Clip to the waterline */
  275.         }
  276.         else {
  277.             ForeColor(blackColor);
  278.             gOnLand = true;                    /* Otherwise we’re on land from the start */
  279.         }
  280.     }
  281.     else {                                    /* Else we’re in the middle of a line and */
  282.         if (oldZ > 0 && *newZ > 0) {        /* Start & end points both above water.. */
  283.             oldZ = *newZ;
  284.         }
  285.         else if (oldZ < 0 && *newZ < 0) {    /* Start & end points both under water... */
  286.             oldZ = *newZ;
  287.             *newZ = 0;                        /* Clip at the waterline */
  288.         }
  289.         else {                                /* We’re now crossing the waterline, so calculate */
  290.                                             /*  the exact point where it dives under */
  291.             scratch = (float) (*newZ) / (*newZ - oldZ);                /* Proportion of the line that’s */
  292.             waterX = (short) ((oldX - *newX) * scratch) + *newX;    /*  below the water */
  293.             waterY = (short) ((oldY - *newY) * scratch) + *newY;
  294.             waterZ = 0;
  295.  
  296.             PlotTo(waterX, waterY, waterZ);    /* Draw to the waterline first */
  297.             
  298.             /* The plot from the waterline to the endpoint in the new color is done elsewhere */
  299.             if (*newZ > 0) {                /* Emerging from the water */
  300.                 ForeColor(blackColor);
  301.                 gOnLand = true;
  302.                 oldZ = *newZ;
  303.             }
  304.             else {                            /* Diving into the water. */
  305.                 ForeColor(blueColor);
  306.                 gOnLand = false;
  307.                 oldZ = *newZ;
  308.                 *newZ = 0;
  309.             }
  310.         }
  311.     }
  312.     oldX = *newX;                            /* Save the real endpoint of the vector */
  313.     oldY = *newY;                            /*  to use as the start of the next call */
  314. }
  315.  
  316.  
  317. /*
  318.     ScaleValue
  319.     
  320.     Computes base * numer / denom with long intermediate
  321. */
  322. short ScaleValue(short base, short numer, short denom)
  323. {
  324.     long            temp;
  325.  
  326.     temp = (long) base * (long) numer;
  327.     temp /= (long) denom;
  328.     return (short) temp;
  329. }
  330.  
  331.  
  332. /*
  333.     PlotTo
  334.     
  335.     This function converts a 3-D line to a 2-D line and plots it
  336. */
  337. void PlotTo(short x, short y, short z)
  338. {
  339.     Rotate(&x, &y);         /* Rotate 30 deg. towards Y in the XY plane */
  340.     TiltDown(&x, &z);       /* Tip 36 deg. down in the ZX plane */
  341.     x /= 25;                /* Scale 10K to 400. */
  342.     y /= 25;
  343.     z /= 25;
  344.     DrawLine(y, z);         /* Show the YZ planar projection. */
  345. }
  346.  
  347.  
  348. /*
  349.     Rotate
  350.     
  351.     This function rotates a point in the XY plane a + 30 degress.
  352. */ 
  353. void Rotate(short *x, short *y)
  354. {
  355.     Cordic(x, y, 5, 17);
  356. }
  357.  
  358.  
  359. /*
  360.     TiltDown
  361.     
  362.     This function rotates a point in the XZ plane a + or - 36 degress.
  363. */
  364. void TiltDown(short *x, short *z)
  365. {
  366.     Cordic(x, z, 5, (gContourType == kStyleMountains) ? 20 : -20);
  367. }
  368.  
  369.  
  370. /*
  371.     DrawLine
  372.     
  373.     This function draws a line from the last endpoint
  374. */
  375. void DrawLine(short x, short y)
  376. {
  377.     x += x/10 + 10;                         /* Compute x1.1 + tiny offset */
  378.     if (gContourType == kStyleMountains)
  379.             y = 220 - y;                    /* Move the baseline for mountains */
  380.     else
  381.             y = 80 - y;
  382.  
  383.     if (gAtLineStart || !gOnLand)            /* Only a point then */
  384.         ScaledMoveTo(x, y);
  385.         
  386.     ScaledLineTo(x, y);
  387.     gAtLineStart = false;
  388. }
  389.  
  390.  
  391. /*
  392.     Cordic
  393.     
  394.     This function spins the XY vector ‘count’ steps to the left 
  395.     using a CORDIC algorithm with a shift factor of ‘scale.’
  396.     Rotates atan(1/(2^scale)) degrees/step (e.g. scale of 5 is 
  397.     1.79 deg/step;  4 = 3.57 d/s...)
  398.     
  399.     *x and *y should be large for accuracy.
  400. */
  401. void Cordic(short *x, short *y, short scale, short count)      
  402. {
  403.     short            tempX, tempY;
  404.  
  405.     tempX = *x;
  406.     tempY = *y;
  407.     if (count > 0)                        /* Positive count is CCW (left) */
  408.         for (; count; count--) {
  409.             tempX -= (tempY >> scale);
  410.             tempY += (tempX >> scale);
  411.         }
  412.     else                                /* Negative is CW (right) */
  413.         for (; count; count++) {
  414.             tempX += (tempY >> scale);
  415.             tempY -= (tempX >> scale);
  416.         }
  417.     *x = tempX;
  418.     *y = tempY;
  419. }
  420.  
  421.  
  422. /*
  423.     ScaledMoveTo
  424.     
  425.     This function performs a scaled MoveTo by scaling the given
  426.     point from MacPlus screen coordinates to the size of the
  427.     current main window.
  428. */
  429. void ScaledMoveTo(short x, short y)
  430. {
  431.     MoveTo((long)x * (long)gMainWindowWidth / kOriginalScreenX, 
  432.             (long)y * (long)gMainWindowHeight / kOriginalScreenY);
  433. }
  434.  
  435.  
  436. /*
  437.     ScaledLineTo
  438.  
  439.     This function performs a scaled LineTo by scaling the given
  440.     point from MacPlus screen coordinates to the size of the
  441.     current main window.
  442. */
  443. void ScaledLineTo(short x, short y)
  444. {
  445.     LineTo((long)x * (long)gMainWindowWidth / kOriginalScreenX, 
  446.             (long)y * (long)gMainWindowHeight / kOriginalScreenY);
  447. }
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.